UFABC - ESTI019 - Codificação de Sinais Multimídia

Laboratório 6 - PDS da Voz

Prof. Mário Minami </h2>

OBJETIVOS:

  1. Gravar Arquivos de Áudio com dígitos, números gerais, texto lido e poesia
  2. Leitura de Arquivos de Áudio e janelamento
  3. Cálculo das Energias de Tempo Curto
  4. Cálculo dos Espectrogramas
  5. Determinação do Pitch, da Frequência Fundamental e das Formantes ($f_1$ a $f_4$) de Algumas Vogais
  6. Determinação de fonemas surdos, sonoros, consoantes gerais e plosivos

1. Gravar Arquivos de Áudio com dígitos, números gerais, texto lido e poesia

Usando o Audacity, ou outro programa de áudio, grave arquivos com:

  • Dígitos
  • Números Gerais
  • Texto lido
  • Poesia declamada

Carregando áudios gravados

In [1]:
# Nomes dos arquivos gravados
audio2 = 'RA11201721076.wav'
audio3 = 'Burrinho_BrunoRodrigues.wav'
audio4 = 'Camoes_BrunoRodrigues.wav'
In [2]:
from google.colab import drive
drive.mount('/content/drive')
Drive already mounted at /content/drive; to attempt to forcibly remount, call drive.mount("/content/drive", force_remount=True).
In [3]:
import numpy as np
import matplotlib.pyplot as plt
import librosa
import librosa.display
import IPython.display
import os
os.chdir("/content/drive/MyDrive/UFABC2019/CSM/lab6")
In [4]:
print(audio2)
v2, sr2 = librosa.load(audio2)
IPython.display.Audio(data=v2, rate=sr2)
RA11201721076.wav
Out[4]:
In [5]:
print(audio3)
v3, sr3 = librosa.load(audio3)
IPython.display.Audio(data=v3, rate=sr3)
Burrinho_BrunoRodrigues.wav
Out[5]:
In [6]:
print(audio4)
v4, sr4 = librosa.load(audio4)
IPython.display.Audio(data=v4, rate=sr4)
Camoes_BrunoRodrigues.wav
Out[6]:

2. Leitura de Arquivos de Áudio e janelamento

In [7]:
#OBS.: insira nome do arquivo WAV
audio1 = 'Entre_Leva_Catia_Falada.wav'
print(audio1)
v1 , sr1 = librosa.load(audio1)
print(type(v1), type(sr1))
print(v1.shape, sr1)
# Player será aberto! AGUARDE até abrir!
IPython.display.Audio(data=v1, rate=sr1)
Entre_Leva_Catia_Falada.wav
<class 'numpy.ndarray'> <class 'int'>
(292805,) 22050
Out[7]:
In [8]:
plt.figure()
fig, ax = plt.subplots(figsize=(15, 5))
librosa.display.waveplot(v1, sr=sr1)
plt.title('Voz da Catia' + audio1)
Out[8]:
Text(0.5, 1.0, 'Voz da CatiaEntre_Leva_Catia_Falada.wav')
<Figure size 432x288 with 0 Axes>

2.1 Definição dos Parâmetros da Análise

In [9]:
print('Frequência de Amostragem', sr1)
Frequência de Amostragem 22050
In [10]:
fa = sr1
print(fa)
22050
In [11]:
Ts = 0.04   # Tempo de duração do segmento em segundos
Nj = int(Ts*fa) # Número de pontos da Janela
print('Tamanho do Segmento', Nj)
Tamanho do Segmento 882
In [12]:
Nseg = int(len(v1)/Nj)
Nover = int(Nj*0.5)
print('Número de Segmentos no Arquivo', Nseg, '. Pontos Soprepostos', Nover )
Número de Segmentos no Arquivo 331 . Pontos Soprepostos 441

2.2 Obtendo uma Janela de Hamming

In [13]:
from scipy import signal
hm = signal.get_window('hamming', Nj)
plt.plot(hm); plt.title('Janela de Hamming')
Out[13]:
Text(0.5, 1.0, 'Janela de Hamming')

3. Energia de Tempo Curto

3.1 Cálculo para arquivo de teste

In [14]:
Nover = int(Nj*0.5)
Nseg = int(len(v1)/Nj)
E = []
for l in range(1, Nseg):
    xjan = v1[(l-1)*Nj+Nover:l*Nj+Nover]*hm
    x2 = list(np.array(xjan**2))
    aux = sum(x2)/Nj
    E.append(aux)
E = 10*np.log10(E)
Emin = np.min(E)  # calcula nível de ruído de fundo
plt.figure
fig, ax = plt.subplots(figsize=(15, 3))
plt.plot(E - Emin)
plt.title('Energia da Voz' + audio1)
plt.ylabel('Energia[db]'); plt.xlabel('Segmento')
Out[14]:
Text(0.5, 0, 'Segmento')

3.2 Agora leia os seus arquivos gravados e:

Determine o Contorno de Energia para três arquivos que vocês gravaram:

  1. dígitos
  2. voz falada
  3. voz declamada (poema)
In [15]:
# Definindo função para realizar todo o processamento
def contorno_energia(audio_nome):
    v1, sr1 = librosa.load(audio_nome)
    fa = sr1
    Ts = 0.04   # Tempo de duração do segmento em segundos
    Nj = int(Ts*fa) # Número de pontos da Janela
    Nseg = int(len(v1)/Nj)
    Nover = int(Nj*0.5)
    hm = signal.get_window('hamming', Nj)
    Nover = int(Nj*0.5)
    Nseg = int(len(v1)/Nj)
    E = []
    for l in range(1, Nseg):
        xjan = v1[(l-1)*Nj+Nover:l*Nj+Nover]*hm
        x2 = list(np.array(xjan**2))
        aux = sum(x2)/Nj
        E.append(aux)
    E = 10*np.log10(E)
    Emin = np.min(E)  # calcula nível de ruído de fundo
    plt.figure
    fig, ax = plt.subplots(figsize=(15, 3))
    plt.plot(E - Emin)
    plt.title('Energia da Voz ' + audio_nome)
    plt.ylabel('Energia[db]'); plt.xlabel('Segmento')

    plt.savefig('1_' + audio_nome + ".png", bbox_inches='tight')
In [16]:
contorno_energia(audio2)
contorno_energia(audio3)
contorno_energia(audio4)

4. Espectrogramas

4.1 Visualização do Espectrograma para Arquivo de Teste

In [17]:
import matplotlib.pyplot as plt
plt.figure(figsize=(12, 8))
D = librosa.amplitude_to_db(np.abs(librosa.stft(v1)), ref=np.max)
fig, ax = plt.subplots(figsize=(15, 10))
librosa.display.specshow(D, x_axis='time',y_axis='linear')
plt.colorbar(format='%+2.0f dB')
plt.title('Potência e Espectrograma Linear na Frequência'+ audio1)
Out[17]:
Text(0.5, 1.0, 'Potência e Espectrograma Linear na FrequênciaEntre_Leva_Catia_Falada.wav')
<Figure size 864x576 with 0 Axes>

4.2 Agora com os seus arquivos

Faça os espectrogramas para os arquivos que vocês gravaram e calculem o contorno de energia:

  • Dígitos
  • Texto Lido
  • Poesia
In [18]:
# Definindo função para realizar todo o processamento
def espectrograma(audio_nome):
    v1, sr1 = librosa.load(audio_nome)
    plt.figure(figsize=(12, 8))
    D = librosa.amplitude_to_db(np.abs(librosa.stft(v1)), ref=np.max)
    fig, ax = plt.subplots(figsize=(15, 10))
    librosa.display.specshow(D, x_axis='time',y_axis='linear')
    plt.colorbar(format='%+2.0f dB')
    plt.title('Potência e Espectrograma Linear na Frequência'+ audio_nome)

    plt.savefig('2_' + audio_nome + ".png", bbox_inches='tight')
In [19]:
espectrograma(audio2)
espectrograma(audio3)
espectrograma(audio4)
Output hidden; open in https://colab.research.google.com to view.

5. Determinação do Pitch e da F0

5.1 Pitch do Arquivo Teste1

In [20]:
# Segmente um fonema que tenha Pitch, p.ex "En" de "Entre"
v1En = v1[4000:16000]
IPython.display.Audio(data=v1En, rate=sr1)
Out[20]:
In [21]:
from matplotlib.ticker import (MultipleLocator, FormatStrFormatter, AutoMinorLocator)
acEn = librosa.autocorrelate(v1En, max_size= sr1/32)
fig, ax = plt.subplots(figsize=(15, 5))
ax.xaxis.set_major_locator(MultipleLocator(1))
y1 = acEn[1:400]
x1 = range(len(y1))
xx = [i*1000/sr1 for i in x1]
plt.grid(True)
ax.plot(xx,y1)

plt.title('Auto-correlação 1')
plt.xlabel('tempo em [ms]')
plt.show()

O Período de Pitch ($T_{0}$) será o intervalo entre picos sucessivos
($T_{0}$) = 3.5 ms
A Frequência Fundamental ($f_0$) será o inverso do periódo de Pitch
($f_0$) =~ 288 Hz

5.2 Pitch do Arquivo Teste2

In [22]:
# Segmente outro fonema que tenha Pitch, p.ex "Ag" de "Agora"
v1A = v1[48000:56000]
IPython.display.Audio(data=v1A, rate=sr1)
Out[22]:
In [23]:
acA = librosa.autocorrelate(v1A, max_size= sr1/32)
fig, ax2 = plt.subplots(figsize=(15, 5))
ax2.xaxis.set_major_locator(MultipleLocator(1))
y2 = acA[1:500]
x2 = range(len(y2))
xx2 = [i*1000/sr1 for i in x2]
plt.grid(True)
ax2.plot(xx2,y2)

plt.title('Auto-correlação 2')
plt.xlabel('tempo em [ms]')
plt.show()

Determine o Período de Pitch e a Fundamental desta vogal.

O Período de Pitch ($T_{0}$) será o intervalo entre picos sucessivos
($T_{0}$) = 4.5 ms
A Frequência Fundamental ($f_0$) será o inverso do periódo de Pitch
($f_0$) =~ 222 Hz

Agora com cada um dos seus arquivos:

Determine o Pitch e a $f_0$ da vogais que desejarem dos seus arquivos, para as versões:

  1. Dígitos
  2. Falada
  3. Declamada
In [24]:
def auto_correlacao(ini, fim, audio_nome, fonema_nome):
    v1, sr1 = librosa.load(audio_nome)
    v1A = v1[ini:fim]
    acA = librosa.autocorrelate(v1A, max_size= sr1/32)
    fig, ax2 = plt.subplots(figsize=(15, 5))
    ax2.xaxis.set_major_locator(MultipleLocator(1))
    y2 = acA[1:500]
    x2 = range(len(y2))
    xx2 = [i*1000/sr1 for i in x2]
    plt.grid(True)
    ax2.plot(xx2,y2)

    plt.title('Auto-correlação '+audio_nome+" "+fonema_nome)
    plt.xlabel('tempo em [ms]')
    plt.show()

    plt.savefig('3_'+audio_nome + ".png", bbox_inches='tight')
In [25]:
def plot_audio(audio_nome):
    v1, sr1 = librosa.load(audio_nome)
    plt.figure()
    fig, ax = plt.subplots(figsize=(15, 5))
    librosa.display.waveplot(v1, sr=sr1)
    plt.title(audio_nome)

1. Dígitos

In [26]:
plot_audio(audio2)
<Figure size 432x288 with 0 Axes>
In [27]:
# "Do" do número "Dois"
ini = 50000
fim = 58000
v2, sr2 = librosa.load(audio2)
v2A = v2[ini:fim]
IPython.display.Audio(data=v2A, rate=sr2)
Out[27]:
In [28]:
# "Do" do número "Dois"
auto_correlacao(ini, fim, audio2, "'Do' do número 'Dois'")
<Figure size 432x288 with 0 Axes>

Período de Pitch e a Fundamental - "Do" do número "Dois"

O Período de Pitch ($T_{0}$) será o intervalo entre picos sucessivos
($T_{0}$) = 8.2 ms
A Frequência Fundamental ($f_0$) será o inverso do periódo de Pitch
($f_0$) =~ 122 Hz

2. Falada

In [29]:
plot_audio(audio3)
<Figure size 432x288 with 0 Axes>
In [30]:
# "ga" da palavra "folgado"
ini = 18000
fim = 23000
v3, sr3 = librosa.load(audio3)
v3A = v3[ini:fim]
IPython.display.Audio(data=v3A, rate=sr3)
Out[30]:
In [31]:
# "ga" da palavra "folgado"
auto_correlacao(ini, fim, audio3, "'ga' da palavra 'folgado'")
<Figure size 432x288 with 0 Axes>

Período de Pitch e a Fundamental - "ga" da palavra "folgado"

O Período de Pitch ($T_{0}$) será o intervalo entre picos sucessivos
($T_{0}$) = 8.1 ms
A Frequência Fundamental ($f_0$) será o inverso do período de Pitch
($f_0$) =~ 123 Hz

3. Cantada

In [32]:
plot_audio(audio4)
<Figure size 432x288 with 0 Axes>
In [33]:
# "a" da palavra "alegre"
ini = 180000
fim = 181500
v4, sr4 = librosa.load(audio4)
v4A = v4[ini:fim]
IPython.display.Audio(data=v4A, rate=sr4)
Out[33]:
In [34]:
# "a" da palavra "alegre"
auto_correlacao(ini, fim, audio3, "'a' da palavra 'alegre'")
<Figure size 432x288 with 0 Axes>

Período de Pitch e a Fundamental - "a" da palavra "alegre"

O Período de Pitch ($T_{0}$) será o intervalo entre picos sucessivos
($T_{0}$) = 8.0 ms
A Frequência Fundamental ($f_0$) será o inverso do período de Pitch
($f_0$) = 125 Hz

5.3 Determinação das Formantes

5.3.a Formantes do trecho de teste

In [35]:
# AUDIO DE "En" em v1En
f, Pxx_spec = signal.periodogram(v1En, fa, 'flattop', scaling='spectrum')
lf = len(f)
fig, AX = plt.subplots(figsize=(15, 5))
AX.xaxis.set_major_locator(MultipleLocator(100))
AX.plot(f[:int(lf/4)], 10*np.log10(np.sqrt(Pxx_spec[:int(lf/4)])))
plt.xlabel('Frequência [Hz]')
plt.ylabel('Log-spectro [dB]')
plt.title('Espectro da Vogal /En/ de <Entre> de '+audio1)
plt.grid(True)
plt.show()

5.3.b Os quatro primeros picos no espectro são as formantes $f_1$ a $f_4$

$f_1$ = 250 Hz $f_2$ = 500 Hz $f_3$ = 750 Hz $f_4$ = 1000 Hz

5.4 Agora com seus arquivos

Determine as formantes das vogais dos arquivos que vocês calcularam os espectrogramas

In [36]:
# Definindo funções
def formantes(v1A, sr1, audio_nome):
    f, Pxx_spec = signal.periodogram(v1A, sr1, 'flattop', scaling='spectrum')
    lf = len(f)
    fig, AX = plt.subplots(figsize=(15, 5))
    AX.xaxis.set_major_locator(MultipleLocator(100))
    AX.plot(f[:int(lf/4)], 10*np.log10(np.sqrt(Pxx_spec[:int(lf/4)])))
    plt.xlabel('Frequência [Hz]')
    plt.ylabel('Log-spectro [dB]')
    plt.title('Espectro da Vogal de '+audio_nome)
    plt.grid(True)
    plt.show()

    plt.savefig('4_'+audio_nome + ".png", bbox_inches='tight')
In [37]:
#"Do" do número "Dois"
formantes(v2A, sr2, audio2)
<Figure size 432x288 with 0 Axes>

$f_1$ = 120 Hz $f_2$ = 250 Hz $f_3$ = 490 Hz $f_4$ = 600 Hz

In [38]:
# "ga" da palavra "folgado"
formantes(v3A, sr3, audio3)
<Figure size 432x288 with 0 Axes>

$f_1$ = 120 Hz $f_2$ = 550 Hz $f_3$ = 700 Hz $f_4$ = 800 Hz

In [39]:
# "a" da palavra "alegre"
formantes(v4A, sr4, audio4)
<Figure size 432x288 with 0 Axes>

$f_1$ = 550 Hz $f_2$ = 670 Hz $f_3$ = 1230 Hz $f_4$ = 1550 Hz

6. Determinação de Consoantes e Plosivos

Usando alguns de seus arquivos, no espectrograma, determine algumas consoantes e em especial as plosivas

Camões

Utilizando o Audacity, determinei os intervalos que continham as consoantes desejadas

In [40]:
print(audio4)
v4, sr4 = librosa.load(audio4)
IPython.display.Audio(data=v4, rate=sr4)
Camoes_BrunoRodrigues.wav
Out[40]:
In [41]:
# Selecionando os 5 primeiros segundos do audio Camões
v4, sr4 = librosa.load(audio4)
v4 = v4[:sr4*5]

# Plotando Espectrograma
plt.figure(figsize=(20, 8))
D = librosa.amplitude_to_db(np.abs(librosa.stft(v4)), ref=np.max)
fig, ax = plt.subplots(figsize=(20, 6))
librosa.display.specshow(D, x_axis='time',y_axis='linear')
plt.colorbar(format='%+2.0f dB')
plt.title('Potência e Espectrograma Linear na Frequência '+ audio4)

# Linhas nas regiões de consoantes
# "C de Campos"
plt.axvline(x=0.52, ymin=0, ymax=1, color="red", lw=0.8,label="C de Campos")
plt.axvline(x=0.62, ymin=0, ymax=1, color="red", lw=0.8)
# "P de Campos"
plt.axvline(x=0.82, ymin=0, ymax=1, color="green", lw=0.8, label="P de Campos")
plt.axvline(x=0.92, ymin=0, ymax=1, color="green", lw=0.8)
# "T de Tornai-vos"
plt.axvline(x=2.80, ymin=0, ymax=1, color="white", lw=0.8, label="T de Tornai-vos")
plt.axvline(x=2.89, ymin=0, ymax=1, color="white", lw=0.8)
# "V de Tornai-vos"
plt.axvline(x=3.28, ymin=0, ymax=1, color="yellow", lw=0.8, label="V de Tornai-vos")
plt.axvline(x=3.36, ymin=0, ymax=1, color="yellow", lw=0.8)
# "G de Agora"
plt.axvline(x=3.61, ymin=0, ymax=1, color="orange", lw=0.8, label="G de Agora")
plt.axvline(x=3.71, ymin=0, ymax=1, color="orange", lw=0.8)

plt.legend()

plt.savefig('5_'+audio4 + ".png", bbox_inches='tight')
<Figure size 1440x576 with 0 Axes>